package com.example.demo.service.iml;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.example.demo.config.AliyunConfig;
import com.example.demo.config.WechatConfig;
import com.example.demo.mapper.AlarmDeviceConfigMapper;
import com.example.demo.model.dto.WechatSubscribeMessageDTO;
import com.example.demo.model.entity.DeviceConfig;
import com.example.demo.service.*;
import com.example.demo.model.dto.SendSmsRequestDTO;
import com.example.demo.model.dto.SingleCallByTtsRequestDTO;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AlarmDeviceConfigServiceImpl extends ServiceImpl<AlarmDeviceConfigMapper, DeviceConfig>
        implements AlarmDeviceConfigService {

    private final AlarmDeviceConfigMapper alarmDeviceConfigMapper;
    private final SmsService smsService;
    private final DyvmsService dyvmsService;
    private final AliyunConfig aliyunConfig;
    private final WechatService wechatService;
    private final WechatConfig wechatConfig;
    private final AlarmNotificationService alarmNotificationService;

    private final WechatCloudDBService cloudDBService; // 添加云数据库服务

    // 定义费用常量
    private static final BigDecimal SMS_COST = new BigDecimal("0.10");
    private static final BigDecimal PHONE_COST = new BigDecimal("0.15");


    public AlarmDeviceConfigServiceImpl(
            AlarmDeviceConfigMapper alarmDeviceConfigMapper,
            SmsService smsService,
            DyvmsService dyvmsService,
            AliyunConfig aliyunConfig,
            WechatService wechatService,
            WechatConfig wechatConfig,
            AlarmNotificationService alarmNotificationService,
            WechatCloudDBService wechatCloudDBService) {
        this.alarmDeviceConfigMapper = alarmDeviceConfigMapper;
        this.smsService = smsService;
        this.dyvmsService = dyvmsService;
        this.aliyunConfig = aliyunConfig;
        this.wechatService = wechatService;
        this.wechatConfig = wechatConfig;
        this.alarmNotificationService = alarmNotificationService;
        this.cloudDBService = wechatCloudDBService; // 引入云数据库服务
    }

    private boolean checkAndDeductBalance(String openid, BigDecimal cost) {
        try {
            // 构造查询条件语句
            String query = String.format(
                    "db.collection(\"users\").where({openid: '%s'}).get()",
                    openid
            );

            // 查询用户余额
            String queryResult = cloudDBService.executeQuery(query);
            log.debug("查询用户余额结果: {}", queryResult);

            // 解析返回的数据
            JSONObject response = JSON.parseObject(queryResult);
            if (response == null || response.isEmpty()) {
                log.warn("未找到用户数据, openid: {}", openid);
                return false;
            }

            JSONArray data = response.getJSONArray("data");
            if (data == null || data.isEmpty()) {
                log.warn("用户数据为空, openid: {}", openid);
                return false;
            }

            JSONObject userInfo = data.getJSONObject(0);
            BigDecimal balance = userInfo.getBigDecimal("balance");
            if (balance == null) {
                log.warn("用户余额为null，设置为0, openid: {}", openid);
                balance = BigDecimal.ZERO;
            }

            log.info("用户当前余额: {}, 所需费用: {}", balance, cost);

            if (balance.compareTo(cost) >= 0) {
                // 构造更新语句
                String updateQuery = String.format(
                        "db.collection(\"users\").where({openid: '%s'}).update({" +
                                "data: {" +
                                "balance: %s," +
                                "updateTime: '%s'" +
                                "}})",
                        openid,
                        balance.subtract(cost).toString(),
                        LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
                );

                // 执行更新
                String updateResult = cloudDBService.executeUpdate(updateQuery);
                log.info("余额扣除成功，剩余: {}", balance.subtract(cost));
                return true;
            }
            log.warn("用户余额不足，当前余额: {}, 需要: {}", balance, cost);
            return false;
        } catch (Exception e) {
            log.error("检查或扣除余额失败: {}", e.getMessage(), e);
            return false;
        }
    }

    // 同样修改退还余额的方法
    private void refundBalance(String openid, BigDecimal amount) {
        try {
            // 先查询当前余额
            String query = String.format(
                    "db.collection(\"users\").where({openid: '%s'}).get()",
                    openid
            );
            String queryResult = cloudDBService.executeQuery(query);
            JSONObject response = JSON.parseObject(queryResult);
            JSONArray data = response.getJSONArray("data");
            JSONObject userInfo = data.getJSONObject(0);
            BigDecimal currentBalance = userInfo.getBigDecimal("balance");

            // 构造更新语句
            String updateQuery = String.format(
                    "db.collection(\"users\").where({openid: '%s'}).update({" +
                            "data: {" +
                            "balance: %s," +
                            "updateTime: '%s'" +
                            "}})",
                    openid,
                    currentBalance.add(amount).toString(),
                    LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
            );

            cloudDBService.executeUpdate(updateQuery);
            log.info("退还余额成功：{}元", amount);
        } catch (Exception e) {
            log.error("退还余额失败: {}", e.getMessage(), e);
        }
    }

    // 添加电池电量转换方法
    private String calculateBatteryVolume(String powerBt) {
        try {
            float powerValue = Float.parseFloat(powerBt);
            if (powerValue > 3000) {
                float dataVol = (powerValue - 3000) / (4100 - 3000) * 100;
                if (dataVol >= 100) {
                    return "100";
                } else {
                    return String.valueOf((int)dataVol);
                }
            }
            return "0";
        } catch (NumberFormatException e) {
            log.error("电池电量转换失败: {}", e.getMessage());
            return "0";
        }
    }

    // 添加信号强度转换方法
    private String calculateSignalStrength(String signalStr) {
        try {
            float signal = Float.parseFloat(signalStr);
            return String.valueOf((int)(signal / 32.0 * 100)) + "%";
        } catch (NumberFormatException e) {
            log.error("信号强度转换失败: {}", e.getMessage());
            return "0%";
        }
    }

    // 添加保存报警记录的私有方法
    private void saveAlarmRecord(String deviceName, String alarmType, DeviceConfig config,
                                 boolean isAlarm, List<String> notificationMethods, boolean isSuccess,
                                 String powerBt, String signalStrength, String deviceSata) {
        try {
            // 直接使用 Date 对象，而不是格式化的字符串
            String query = String.format(
                    "db.collection(\"alarm_records\").add({" +
                            "data: [{" +
                            "deviceName: '%s'," +
                            "imei: '%s'," +
                            "openid: '%s'," +
                            "alarmType: '%s'," +
                            "status: '%s'," +
                            "processedStatus: '%s'," +
                            "notificationMethods: %s," +
                            "notificationSuccess: %s," +
                            "alarmPhones: %s," +
                            "createTime: new Date()," + // 使用 Date 对象
                            "alarmTimes: %d," +
                            "alarmInterval: %d," +
                            "batteryLevel: '%s'," +
                            "signalStrength: '%s'," +
                            "deviceStatus: '%s'" +
                            "}]" +
                            "})",
                    deviceName,
                    config.getImei(),
                    config.getOpenid(),
                    alarmType,
                    isAlarm ? "报警" : "恢复",
                    processDeviceStatus(alarmType),
                    JSON.toJSONString(notificationMethods),
                    isSuccess,
                    JSON.toJSONString(getValidPhoneNumbers(config)),
                    config.getAlarmTimes(),
                    config.getAlarmInterval(),
                    calculateBatteryVolume(powerBt),
                    calculateSignalStrength(signalStrength),
                    deviceSata
            );

            String result = cloudDBService.executeAdd(query);
            log.info("保存报警记录成功：{}", result);
        } catch (Exception e) {
            log.error("保存报警记录失败: {}", e.getMessage(), e);
        }
    }


    @Override
    public void handleDeviceAlarm(String deviceName, DeviceConfig config, String alarmType,
                                  String powerBt, String signalStrength, String deviceSata) {
        if (config == null) {
            log.warn("设备[{}]配置为空，无法处理报警", deviceName);
            return;
        }

        try {
            List<String> phoneNumbers = getValidPhoneNumbers(config);
            if (phoneNumbers.isEmpty()) {
                log.warn("设备[{}]未配置有效的报警电话号码", deviceName);
                return;
            }

            boolean isSuccess = true;
            List<String> notificationMethods = new ArrayList<>();

            // 微信报警不需要检查余额
            if (config.getWechatAlarm()) {
                try {
                    sendWechatAlarmNotification(deviceName, alarmType, config);
                    notificationMethods.add("微信");
                } catch (Exception e) {
                    log.error("发送微信报警通知失败: {}", e.getMessage(), e);
                    isSuccess = false;
                }
            }

            // 短信报警需要检查余额
            if (config.getSmsAlarm()) {
                boolean smsSuccess = true;
                for (String phoneNumber : phoneNumbers) {
                    if (checkAndDeductBalance(config.getOpenid(), SMS_COST)) {
                        try {
                            SendSmsRequestDTO smsRequest = buildAlarmSmsRequest(deviceName, alarmType, phoneNumber);
                            String response = smsService.sendSms(smsRequest);
                            log.info("发送短信报警通知成功，扣费：{}元", SMS_COST);
                        } catch (Exception e) {
                            log.error("发送短信报警通知失败: {}", e.getMessage(), e);
                            refundBalance(config.getOpenid(), SMS_COST);
                            smsSuccess = false;
                        }
                    } else {
                        log.warn("用户余额不足，无法发送短信报警通知");
                        smsSuccess = false;
                    }
                }
                if (smsSuccess) {
                    notificationMethods.add("短信");
                }
                isSuccess &= smsSuccess;
            }

            // 电话报警需要检查余额
            if (config.getPhoneAlarm()) {
                boolean phoneSuccess = true;
                // 计算所有电话号码总共需要的费用
                BigDecimal totalPhoneCost = PHONE_COST
                        .multiply(new BigDecimal(config.getAlarmTimes()))
                        .multiply(new BigDecimal(phoneNumbers.size()));

                // 一次性检查余额是否足够支付所有号码的所有通知
                if (checkAndDeductBalance(config.getOpenid(), totalPhoneCost)) {
                    try {
                        // 一次性安排所有电话号码的通知
                        alarmNotificationService.scheduleBatchAlarmNotifications(
                                deviceName,
                                alarmType,
                                phoneNumbers,
                                config.getAlarmTimes(),
                                config.getAlarmInterval()
                        );
                        log.info("安排电话报警通知成功，总扣费：{}元", totalPhoneCost);
                    } catch (Exception e) {
                        log.error("安排电话报警通知失败: {}", e.getMessage(), e);
                        refundBalance(config.getOpenid(), totalPhoneCost);
                        phoneSuccess = false;
                    }
                } else {
                    log.warn("用户余额不足，无法发送电话报警通知");
                    phoneSuccess = false;
                }

                if (phoneSuccess) {
                    notificationMethods.add("电话");
                }
                isSuccess &= phoneSuccess;
            }

            // 保存报警记录
            saveAlarmRecord(deviceName, alarmType, config, true, notificationMethods, isSuccess,
                    powerBt, signalStrength, deviceSata);

        } catch (Exception e) {
            log.error("处理设备[{}]报警失败: {}", deviceName, e.getMessage(), e);
        }
    }

    @Override
    public void handleDeviceRecover(String deviceName, DeviceConfig config,
                                    String powerBt, String signalStrength, String deviceSata) {
        if (config == null) {
            log.warn("设备[{}]配置为空，无法处理恢复通知", deviceName);
            return;
        }

        try {
            List<String> phoneNumbers = getValidPhoneNumbers(config);
            if (phoneNumbers.isEmpty()) {
                log.warn("设备[{}]未配置有效的报警电话号码", deviceName);
                return;
            }

            boolean isSuccess = true;
            List<String> notificationMethods = new ArrayList<>();

            // 微信恢复通知
            if (config.getWechatRecover()) {
                try {
                    sendWechatRecoverNotification(deviceName, config);
                    notificationMethods.add("微信");
                } catch (Exception e) {
                    log.error("发送微信恢复通知失败: {}", e.getMessage(), e);
                    isSuccess = false;
                }
            }

            // 短信恢复通知
            if (config.getSmsRecover()) {
                boolean smsSuccess = true;
                for (String phoneNumber : phoneNumbers) {
                    try {
                        SendSmsRequestDTO smsRequest = buildRecoverSmsRequest(deviceName, phoneNumber);
                        String response = smsService.sendSms(smsRequest);
                        log.info("发送短信恢复通知成功");
                    } catch (Exception e) {
                        log.error("发送短信恢复通知失败: {}", e.getMessage(), e);
                        smsSuccess = false;
                    }
                }
                if (smsSuccess) {
                    notificationMethods.add("短信");
                }
                isSuccess &= smsSuccess;
            }

            // 电话恢复通知
            if (config.getPhoneRecover()) {
                boolean phoneSuccess = true;
                for (String phoneNumber : phoneNumbers) {
                    try {
                        SingleCallByTtsRequestDTO callRequest = buildRecoverCallRequest(deviceName, phoneNumber);
                        String response = dyvmsService.singleCallByTts(callRequest);
                        log.info("发送电话恢复通知成功");
                    } catch (Exception e) {
                        log.error("发送电话恢复通知失败: {}", e.getMessage(), e);
                        phoneSuccess = false;
                    }
                }
                if (phoneSuccess) {
                    notificationMethods.add("电话");
                }
                isSuccess &= phoneSuccess;
            }

            // 保存恢复记录，包含电量和信号信息
            saveAlarmRecord(deviceName, "recover", config, false, notificationMethods, isSuccess,
                    powerBt, signalStrength, deviceSata);

        } catch (Exception e) {
            log.error("处理设备[{}]恢复通知失败: {}", deviceName, e.getMessage(), e);
        }
    }


    @Override
    public DeviceConfig getAlarmConfigByDeviceName(String deviceName) {
        try {
            DeviceConfig config = alarmDeviceConfigMapper.findAlarmConfigByDeviceName(deviceName);
            if (config != null) {
                log.info("查询到设备[{}]的报警配置信息: {}", deviceName, config);
            } else {
                log.warn("未查询到设备[{}]的报警配置信息", deviceName);
            }
            return config;
        } catch (Exception e) {
            log.error("查询设备[{}]报警配置信息失败: {}", deviceName, e.getMessage(), e);
            throw new RuntimeException("查询设备报警配置信息失败", e);
        }
    }


    // 获取所有有效的电话号码
    private List<String> getValidPhoneNumbers(DeviceConfig config) {
        return Arrays.asList(
                        config.getAlarmPhone1(),
                        config.getAlarmPhone2(),
                        config.getAlarmPhone3()
                ).stream()
                .filter(StringUtils::hasText)
                .collect(Collectors.toList());
    }

    private SendSmsRequestDTO buildAlarmSmsRequest(String deviceName, String alarmType, String phoneNumber) {
        // 处理显示名称：如果是纯数字且长度大于等于4，取后4位；否则使用完整名称
        String displayName = deviceName;
        if (deviceName.matches("\\d+") && deviceName.length() >= 4) {
            displayName = deviceName.substring(deviceName.length() - 4);
        }

        return SendSmsRequestDTO.builder()
                .phoneNumbers(phoneNumber)
                .templateCode("SMS_185848428")  // 更新为新的模板代码
                .templateParam(String.format("{\"name\":\"%s\",\"number\":\"%s\",\"sate\":\"%s\"}",
                        displayName,       // name字段使用处理后的显示名称
                        deviceName,        // number字段使用原始的设备编号
                        processDeviceStatus(alarmType)  // sate字段使用处理后的状态
                ))
                .signName("渔工科技")  // 更新为新的签名
                .build();
    }

    // 处理设备状态的辅助方法
    private String processDeviceStatus(String deviceSata) {
        return switch (deviceSata) {
            case "offline" -> "停电报警";
            case "IN7_fl_off" -> "防区7断电报警";
            case "IN7_fl_on" -> "防区7恢复有电";
            case "IN8_fl_off" -> "防区8断电报警";
            case "IN8_fl_on" -> "防区8恢复有电";
            case "IN9_fl_off" -> "防区9断电报警";
            case "IN9_fl_on" -> "防区9恢复有电";
            case "IN10_fl_off" -> "防区10断电报警";
            case "IN10_fl_on" -> "防区10恢复有电";
            case "online" -> "正常有电";
            case "power_failure" -> "断电报警";
            default -> deviceSata;
        };
    }

    private SendSmsRequestDTO buildRecoverSmsRequest(String deviceName, String phoneNumber) {
        return SendSmsRequestDTO.builder()
                .phoneNumbers(phoneNumber)
                .templateCode(aliyunConfig.getSms().getTemplateCode())
                .templateParam(String.format("{\"code\":\"%s\",\"status\":\"%s\",\"alarm\":\"%s\",\"power\":\"%s\",\"single\":\"%s\",\"picec\":\"%s\"}",
                        deviceName,      // code字段使用设备名称
                        "恢复",          // status字段表示已恢复
                        "无",           // alarm字段表示无报警
                        "正常",          // power字段表示正常
                        "0",            // single字段使用0表示恢复通知
                        "0"             // picec字段使用0表示恢复通知
                ))
                .signName(aliyunConfig.getSms().getSignName())
                .build();
    }

    private SingleCallByTtsRequestDTO buildAlarmCallRequest(String deviceName, String alarmType, String phoneNumber) {
        return SingleCallByTtsRequestDTO.builder()
                .calledNumber(phoneNumber)
                .calledShowNumber(aliyunConfig.getDyvms().getCalledShowNumber())  // 添加显示号码
                .ttsCode(aliyunConfig.getDyvms().getTtsCode())  // 添加 TTS 模板号

                .build();
    }

    private SingleCallByTtsRequestDTO buildRecoverCallRequest(String deviceName, String phoneNumber) {
        return SingleCallByTtsRequestDTO.builder()
                .calledNumber(phoneNumber)
                .calledShowNumber(aliyunConfig.getDyvms().getCalledShowNumber())  // 添加显示号码
                .ttsCode(aliyunConfig.getDyvms().getTtsCode())  // 添加 TTS 模板号

                .build();
    }

    private void sendWechatAlarmNotification(String deviceName, String alarmType, DeviceConfig config) {
        if (StringUtils.isEmpty(config.getOpenid())) {
            log.warn("设备[{}]未配置openid，无法发送微信通知", deviceName);
            return;
        }

        try {
            // 处理设备状态显示
            String alarmStatus = processDeviceStatus(alarmType);

            Map<String, WechatSubscribeMessageDTO.MsgData> data = new HashMap<>();
            // thing1: 报警设备
            data.put("thing1", WechatSubscribeMessageDTO.MsgData.builder()
                    .value(deviceName)
                    .build());
            // time3: 报警时间
            data.put("time3", WechatSubscribeMessageDTO.MsgData.builder()
                    .value(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                    .build());
            // thing4: 报警原因
            data.put("thing4", WechatSubscribeMessageDTO.MsgData.builder()
                    .value(alarmStatus)  // 使用处理后的报警状态
                    .build());
            // thing5: 报警地点 - 设置默认值避免为空
            data.put("thing5", WechatSubscribeMessageDTO.MsgData.builder()
                    .value("未设置")  // 设置默认值
                    .build());

            WechatSubscribeMessageDTO messageDTO = WechatSubscribeMessageDTO.builder()
                    .touser(config.getOpenid())
                    .template_id(wechatConfig.getTemplateId())
                    .page("pages/device/detail?id=" + deviceName)
                    .lang("zh_CN")
                    .data(data)
                    .build();

            String response = wechatService.sendSubscribeMessage(messageDTO);
            log.info("发送微信报警订阅消息成功，设备：{}，报警类型：{}，响应：{}", deviceName, alarmType, response);
        } catch (Exception e) {
            log.error("发送微信报警订阅消息失败，设备：{}，报警类型：{}，错误：{}", deviceName, alarmType, e.getMessage(), e);
        }
    }

    // 恢复通知也需要相应修改
    private void sendWechatRecoverNotification(String deviceName, DeviceConfig config) {
        if (StringUtils.isEmpty(config.getOpenid())) {
            log.warn("设备[{}]未配置openid，无法发送微信通知", deviceName);
            return;
        }

        try {
            Map<String, WechatSubscribeMessageDTO.MsgData> data = new HashMap<>();
            data.put("thing1", WechatSubscribeMessageDTO.MsgData.builder()
                    .value(deviceName)
                    .build());
            data.put("time3", WechatSubscribeMessageDTO.MsgData.builder()
                    .value(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                    .build());
            data.put("thing4", WechatSubscribeMessageDTO.MsgData.builder()
                    .value("设备恢复正常")
                    .build());
            data.put("thing5", WechatSubscribeMessageDTO.MsgData.builder()
                    .value("未设置")  // 设置默认值
                    .build());

            WechatSubscribeMessageDTO messageDTO = WechatSubscribeMessageDTO.builder()
                    .touser(config.getOpenid())
                    .template_id(wechatConfig.getTemplateId())
                    .page("pages/device/detail?id=" + deviceName)
                    .lang("zh_CN")
                    .data(data)
                    .build();

            String response = wechatService.sendSubscribeMessage(messageDTO);
            log.info("发送微信恢复订阅消息成功，设备：{}，响应：{}", deviceName, response);
        } catch (Exception e) {
            log.error("发送微信恢复订阅消息失败，设备：{}，错误：{}", deviceName, e.getMessage(), e);
        }
    }

}